/**
 * ****************************************************************************
 * Project: RoboBridge
 * ----------------------------------------------------------------------------
 * -------------------------- [c]2012 - KrawallMann ---------------------------
 * ---------------------- http://www.krawallmann.de.tc/ -----------------------
 * ****************************************************************************
 * File: AbstractDevice.java Package: tc.de.krawallmann.robobridge.devices
 * Version: 1.0 Author(s): KrawallMann
 * ****************************************************************************
 * Description:
 * ****************************************************************************
 */
package tc.de.krawallmann.robobridge.devices;

import java.util.HashSet;
import java.util.Set;

import tc.de.krawallmann.robobridge.communication.Command;
import tc.de.krawallmann.robobridge.communication.CommandType;
import tc.de.krawallmann.robobridge.communication.IncomingCommandListener;

/**
 * The Class AbstractDevice is a superclass for all physical devices available
 * on the robot.
 * 
 * @author KrawallMann
 * @version 1.0
 */
public abstract class AbstractDevice implements IncomingCommandListener {
	
	public static final int DEVICE_ID_RP6_BASE =1;
	public static final int DEVICE_ID_RP6_M32 =2;
	public static final int DEVICE_ID_RP6_RNCONTROL =3;
	public static final int DEVICE_ID_RP6_M256 =4;
	public static final int DEVICE_ID_SRF08 =5;
	public static final int DEVICE_ID_CMPS03 =6;
	public static final int DEVICE_ID_LCD03 =7;
	public static final int DEVICE_ID_RP6_DRIVING_LIGHTS =8;
	public static final int DEVICE_ID_CUSTOM_DEVICE_OFFSET =DEVICE_ID_RP6_DRIVING_LIGHTS;
	
	protected transient final int deviceCode;
	/** The device id. */
	protected transient final int deviceId;

	/** The manufacturer. */
	protected transient final String manufacturer;

	/** The model. */
	protected transient final String model;

	/** The robot. */
	protected transient Robot robot;

	/** The listeners. */
	private transient final Set<SensorListener> listeners = new HashSet<SensorListener>();


	public int getDeviceCode() {
		return this.deviceCode;
	}

	public AbstractDevice(Robot robot, int deviceCode, int deviceId, String manufacturer,
			String model) {
		super();
		this.robot = robot;
		this.deviceCode = deviceCode;
		this.deviceId = deviceId;
		this.manufacturer = manufacturer;
		this.model = model;
	}

	/**
	 * Adds the sensor listener.
	 * 
	 * @param listener
	 *            the listener
	 */
	public void addSensorListener(final SensorListener listener) {
		listeners.add(listener);
	}

	/**
	 * Contains relevant data.
	 * 
	 * @param command
	 *            the command
	 * @param parameterClasses
	 *            the parameter classes
	 * @return true, if the command contains data for this sensor and has the
	 *         given parameter types
	 */
	public boolean containsRelevantData(final Command command, final Class<?>... parameterClasses) {
		if (command.getParameters().length == 0) {
			return false;
		}
		if (command.getType() != CommandType.UPDATE_DEVICE_DATA) {
			return false;
		}
		if (command.getParameterClass(0) != Integer.class) {
			return false;
		}
		final Integer deviceId = command.getParameter(0);
		if (deviceId != this.deviceId) {
			return false;
		}

		if (command.getParameters().length >= parameterClasses.length + 2) {
			for (int i = 1; i < Math.min(command.getParameters().length,
					parameterClasses.length + 1); ++i) {
				if (command.getParameter(i) == null
						|| !parameterClasses[i - 1].isAssignableFrom(command.getParameter(i)
								.getClass())) {
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * Fire property change.
	 * 
	 * @param propertyName
	 *            the property name
	 * @param oldValue
	 *            the old value
	 * @param newValue
	 *            the new value
	 */
	public void firePropertyChange(final String propertyName, final Object oldValue,
			final Object newValue) {
		for (final SensorListener l : listeners) {
			l.onSensorValueChanged(this, propertyName, oldValue, newValue);
		}
	}

	/**
	 * Gets the device id.
	 * 
	 * @return the device id
	 */
	public int getDeviceId() {
		return deviceId;
	}

	/**
	 * Gets the manufacturer.
	 * 
	 * @return the manufacturer
	 */
	public String getManufacturer() {
		return manufacturer;
	}

	/**
	 * Gets the model.
	 * 
	 * @return the model
	 */
	public String getModel() {
		return model;
	}

	/**
	 * Gets the robot.
	 * 
	 * @return the robot
	 */
	public Robot getRobot() {
		return robot;
	}

	/**
	 * Removes the sensor listener.
	 * 
	 * @param listener
	 *            the listener
	 */
	public void removeSensorListener(final SensorListener listener) {
		listeners.remove(listener);
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "AbstractDevice [deviceId=" + deviceId + ", manufacturer=" + manufacturer
				+ ", model=" + model + "]";
	}

	/**
	 * Update.
	 */
	public void update() {
		// Do nothing here!
	}
}
